import os
import sys
import logging
import secrets
import string
from datetime import datetime, timedelta, timezone
from flask import Flask, request, jsonify
from flask_sqlalchemy import SQLAlchemy
import time

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler("server.log"),
        logging.StreamHandler(sys.stdout)
    ]
)
logger = logging.getLogger("card_key_server")
# 创建 Flask 应用
app = Flask(__name__)
db_dir = os.path.abspath(os.path.dirname(__file__))
db_path = os.path.join(db_dir, "card_keys.db")
app.config['SQLALCHEMY_DATABASE_URI'] = f'sqlite:///{db_path}'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
# 初始化数据库
db = SQLAlchemy(app)


# 数据模型
class CardKey(db.Model):
    __tablename__ = 'card_keys'

    id = db.Column(db.Integer, primary_key=True)
    card_key = db.Column(db.String(50), unique=True, nullable=False, index=True)
    card_type = db.Column(db.String(10), nullable=False)  # 'time' 或 'count'
    status = db.Column(db.String(20), default="未激活")  # 未激活、已激活、已过期、次数用完
    generate_time = db.Column(db.DateTime, default=datetime.utcnow)
    activate_time = db.Column(db.DateTime)
    expire_time = db.Column(db.DateTime)
    max_uses = db.Column(db.Integer)
    used_count = db.Column(db.Integer, default=0)

    def to_dict(self):
        """将模型转换为字典格式，便于 JSON 序列化"""
        return {
            'id': self.id,
            'card_key': self.card_key,
            'card_type': self.card_type,
            'status': self.status,
            'generate_time': self.generate_time.strftime('%Y-%m-%d') if self.generate_time else None,
            'activate_time': self.activate_time.strftime('%Y-%m-%d') if self.activate_time else None,
            'expire_time': self.expire_time.strftime('%Y-%m-%d') if self.expire_time else None,
            'max_uses': self.max_uses,
            'used_count': self.used_count
        }


# 工具函数
def generate_card_key(length=16):
    """生成随机卡密字符串"""
    characters = string.ascii_uppercase + string.digits
    return ''.join(secrets.choice(characters) for _ in range(length))


def check_card_status(card):
    """检查卡密状态并更新"""
    if card.card_type == "time" and card.expire_time > card.expire_time:
        card.status = "已过期"
        db.session.commit()
    elif card.card_type == "count" and card.max_uses and card.used_count >= card.max_uses:
        card.status = "次数用完"
        db.session.commit()
    return card


@app.route('/api/generate', methods=['POST'])
def generate_card():
    """生成卡密"""
    data = request.json

    # 验证参数
    count = data.get('count', 1)
    if count < 1 or count > 1000:
        return jsonify({"success": False, "message": "生成数量必须在 1-1000 之间"}), 400

    card_type = data.get('card_type')
    if card_type not in ['time', 'count']:
        return jsonify({"success": False, "message": "卡密类型必须是 '时间卡密' 或 '次数卡密'"}), 400

    if card_type == 'time' and 'expire_date' not in data:
        return jsonify({"success": False, "message": "时间限制卡密需要设置过期日期"}), 400

    if card_type == 'count' and 'max_uses' not in data:
        return jsonify({"success": False, "message": "次数限制卡密需要设置最大使用次数"}), 400

    try:
        # 处理过期日期格式
        expire_date = None
        if card_type == 'time':
            try:
                expire_date = datetime.strptime(data['expire_date'], '%Y-%m-%d ')
                expire_date = expire_date.replace(
                    hour=23, minute=59, second=59, microsecond=999999,
                    tzinfo=timezone.utc
                )
            except ValueError:
                return jsonify({"success": False, "message": "过期日期格式不正确，应为 YYYY-MM-DD"}), 400

        max_uses = data.get('max_uses') if card_type == 'count' else ''

        # 生成卡密
        generated = []
        for _ in range(count):
            # 确保卡密唯一
            while True:
                key = generate_card_key()
                if not CardKey.query.filter_by(card_key=key).first():
                    break

            card = CardKey(
                card_key=key,
                card_type=card_type,
                status="未激活",
                expire_time=expire_date,
                max_uses=max_uses
            )
            db.session.add(card)
            generated.append(key)

        db.session.commit()
        logger.info(f"成功生成 {len(generated)} 个卡密")
        return jsonify({"success": True, "count": len(generated), "card_keys": generated[:10]})

    except Exception as e:
        db.session.rollback()
        logger.error(f"生成卡密失败: {str(e)}")
        return jsonify({"success": False, "message": "生成卡密失败", "error": str(e)}), 500


@app.route('/api/list', methods=['GET'])
def list_cards():
    """获取卡密列表"""
    try:
        # 获取筛选参数
        status = request.args.get('status')
        card_type = request.args.get('card_type')
        keyword = request.args.get('keyword')

        query = CardKey.query

        if status:
            query = query.filter(CardKey.status == status)

        if card_type:
            query = query.filter(CardKey.card_type == card_type)

        if keyword:
            query = query.filter(CardKey.card_key.contains(keyword))

        # 获取分页参数
        page = int(request.args.get('page', 1))
        per_page = min(int(request.args.get('per_page', 20)), 100)

        # 检查并更新卡密状态
        cards = query.all()
        for card in cards:
            check_card_status(card)

        # 应用分页
        paginated = query.order_by(CardKey.generate_time.desc()).paginate(
            page=page, per_page=per_page, error_out=False
        )

        result = {
            "success": True,
            "total": paginated.total,
            "pages": paginated.pages,
            "page": page,
            "per_page": per_page,
            "cards": [card.to_dict() for card in paginated.items]
        }

        return jsonify(result)

    except Exception as e:
        logger.error(f"获取卡密列表失败: {str(e)}")
        return jsonify({"success": False, "message": "获取卡密列表失败", "error": str(e)}), 500


@app.route('/api/use', methods=['POST'])
def use_card():
    """使用卡密"""
    data = request.json
    card_key = data.get('card_key')

    if not card_key:
        return jsonify({"success": False, "message": "卡密不能为空"}), 200

    try:
        card = CardKey.query.filter_by(card_key=card_key).first()

        if not card:
            return jsonify({"success": False, "message": "卡密不存在"}), 200

        # 检查卡密状态
        card = check_card_status(card)

        if card.status != "已激活":
            return jsonify({"success": False, "message": f"卡密状态为: {card.status}"}), 200

        # 使用卡密
        card.activate_time = datetime.utcnow()

        # 检查是否需要更新状态为"次数用完"
        if card.card_type == "count" and card.used_count >= card.max_uses:
            card.status = "次数用完"

        db.session.commit()

        return jsonify({
            "success": True,
            "message": "卡密使用成功",
            "card": card.to_dict()
        })

    except Exception as e:
        db.session.rollback()
        logger.error(f"使用卡密失败: {str(e)}")
        return jsonify({"success": False, "message": "使用卡密失败", "error": str(e)}), 500


@app.route('/api/activate', methods=['POST'])
def activate_card():
    """激活卡密"""
    data = request.json
    card_key = data.get('card_key')
    if not card_key:
        return jsonify({"success": False, "message": "卡密不能为空"}), 200
    card = CardKey.query.filter_by(card_key=card_key).first()

    if not card:
        return jsonify({"success": False, "message": "卡密不存在"}), 200

    card = check_card_status(card)
    if card.status != '未激活':
        return jsonify({"success": False, "message": "卡密当前状态不能激活"}), 200
    card.status = "已激活"
    db.session.commit()
    logger.info(f"卡密 {card_key} 已激活")

    return jsonify({"success": True, "message": "卡密已激活"})


@app.route('/api/reducecount', methods=['POST'])
def reduce_count():
    """扣减使用次数"""
    data = request.json
    card_key = data.get('card_key')
    if not card_key:
        return jsonify({"success": False, "message": "卡密不能为空"}), 200
    card = CardKey.query.filter_by(card_key=card_key).first()

    if not card:
        return jsonify({"success": False, "message": "卡密不存在"}), 200
    if card.card_type == 'time':
        return jsonify({"success": False, "message": "时间卡密不需要扣减次数"}), 200
    card = check_card_status(card)
    if card.status == '次数用完':
        return jsonify({"success": False, "message": "卡密次数已用完"})
    card.used_count = card.used_count + 1
    db.session.commit()
    return jsonify({"success": True, "message": "卡密扣减成功"})


@app.route('/api/delete', methods=['POST'])
def delete_card():
    """删除卡密"""
    data = request.json
    card_key = data.get('card_key')

    if not card_key:
        return jsonify({"success": False, "message": "卡密不能为空"}), 400

    try:
        card = CardKey.query.filter_by(card_key=card_key).first()

        if not card:
            return jsonify({"success": False, "message": "卡密不存在"}), 404

        db.session.delete(card)
        db.session.commit()
        logger.info(f"卡密 {card_key} 已删除")

        return jsonify({"success": True, "message": "卡密已删除"})

    except Exception as e:
        db.session.rollback()
        logger.error(f"删除卡密失败: {str(e)}")
        return jsonify({"success": False, "message": "删除卡密失败", "error": str(e)}), 500


# 数据库初始化函数
def init_database():
    """初始化数据库并创建表结构"""
    try:
        # 确保数据库目录存在
        if not os.path.exists(db_dir):
            os.makedirs(db_dir)
            logger.info(f"创建数据库目录: {db_dir}")

        # 检查数据库文件是否存在
        db_exists = os.path.exists(db_path)

        # 创建所有表
        with app.app_context():
            db.create_all()

            # 如果是新创建的数据库，添加一些基本信息
            if not db_exists:
                logger.info(f"创建新数据库: {db_path}")
                logger.info("数据库初始化完成")
            else:
                logger.info(f"使用现有数据库: {db_path}")

        return True

    except Exception as e:
        logger.critical(f"数据库初始化失败: {str(e)}")
        return False


# 请求耗时监控中间件
@app.before_request
def before_request():
    request.start_time = time.time()


@app.after_request
def after_request(response):
    if hasattr(request, 'start_time'):
        elapsed = time.time() - request.start_time
        print(f"请求 {request.path} 耗时: {elapsed:.3f}秒")
    return response


if __name__ == '__main__':
    init_database()
    try:
        # 初始化数据库
        if init_database():
            logger.info("服务启动成功，监听端口 5000")
            app.run(debug=True, host='0.0.0.0', port=5000)
        else:
            logger.critical("数据库初始化失败，服务无法启动")
            sys.exit(1)
    except Exception as e:
        logger.critical(f"服务启动失败: {str(e)}")
        import traceback

        traceback.print_exc()  # 打印完整堆栈跟踪
        sys.exit(1)
